#ifndef	INCOGNITO_INCOGNITO_H
#define	INCOGNITO_INCOGNITO_H

#include <chord_types.h>
#include <chord.h>
#include "incognito_proto.h"
#include "keymngr.h"
#include "encmngr.h"

class vnode;
class dhash;
class dhashcli;
class dhash_block;
class encmngr;

typedef callback<void,bigint>::ptr cb_dh_exchange;

class incognito {
	public:
		static ref<incognito> produce_incognito (ptr<vnode> v, ref<dhash> dh);
		virtual ~incognito() = 0;
		virtual void print_stats () = 0;

		virtual void start () = 0;
		virtual void stop () = 0;

};

class incognito_impl : public incognito, public virtual refcount {
		typedef callback<void, ptr<incognito_raw_request> >::ptr cb_onrm;
	public:
		incognito_impl (ptr<vnode> v, ref<dhash> dh);
		~incognito_impl ();
		void print_stats ();
		// ???
 		void stop ();
		// ???
		void start ();
		// "Heartbeat" fn
		void onTick();
		// Called to handle remote calls 
		void dispatch (user_args *a);
	// {{{ Store
	//    {{{ Store - not encrypted packets
	public:
		// Process new raw (not encrypted) store request
		void on_new_raw_store_req(const incognito_store_arg& req);
		// find_successor callback for on_new_raw_store_req
		void on_new_raw_store_req_cb(ptr<incognito_store_arg> req, vec<chord_node> s, route search_path, chordstat status);
	protected:
		// Called by dispatch() - handle INCOGNITOPROC_STORE
		void on_store(user_args *a);
		// Publish request in DHash
		void publish(const incognito_store_arg& req);
		// Called by on_new_raw_message: publish and send reply
		void publish(cb_onrm cb, ptr<incognito_raw_request> raw_msg);

		// Callback for dhcli->insert
		void publish_insert_cb (dhash_stat status, vec<chordID> path);
		// Callback for dhcli->insert in publish(user_args *a, ptr<incognito_raw_request> raw_msg)
		void publish_insert_cb2 (cb_onrm, dhash_stat status, vec<chordID> path);
	//    }}}
	//    {{{ Store - encrypted packets
	public:
		// Call INCOGNITOPROC_ENC_STORE on node n
		void store_encrypted_data(chord_node &n,unsigned int seq,char *buf,size_t buf_size);
	protected:
		// Callback for doRPC in store_encrypted_data
		void store_encrypted_data_cb(clnt_stat err);
		// Called by dispatch() - handle INCOGNITOPROC_ENC_STORE
		void on_enc_store(user_args *a);
		// Callback for encmngr::decrypt()
		void on_enc_store_decrypt_cb(user_args *a, incognito_store_arg req, decryptres res);
	//    }}}
	// }}} 

	// {{{ Fetch
	protected:
		// Called by dispatch() - handle INCOGNITOPROC_FETCH
		void on_fetch(user_args *a);
		// Callback for retrieve() in on_fetch 
		void on_fetch_retrieve_cb(user_args *a, dhash_stat status, ptr<dhash_block> block, route path);

		// Called by on_new_raw_message
		void fetch(cb_onrm cb, ptr<incognito_raw_request> raw_msg);
		void on_fetch_cb(user_args *a, ptr<incognito_raw_request> raw_msg);
		void fetch_retrieve_cb(cb_onrm cb, dhash_stat status, ptr<dhash_block> block, route path);
		//REMOVEME: void fetch_retrieve_cb(user_args *a, dhash_stat status, ptr<dhash_block> block, route path);
	// }}} 
	// {{{ Encrypted messages
	protected:
		// Called by dispatch() - handle INCOGNITOPROC_ENC_MESSAGE
		void on_enc_message(user_args *a);

		// Callback for decrypt() in on_enc_message
		void on_enc_message_decrypt_cb(user_args *a, ptr<incognito_raw_request> raw_msg, encmngr::decrypt_res res);
		
		// Callback for encrypt() in on_enc_message_decrypt_cb
//REMOVE:		void on_enc_message_decrypt_error_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res);

		// All not encrypted messages go though this function
		void on_new_raw_message(ptr<incognito_raw_request> raw_msg, cb_onrm cb);

		// Callback for delaycb in on_new_raw_message_delay_cb
		void on_new_raw_message_delay_cb(ptr<incognito_raw_request> raw_msg, incognito_impl::cb_onrm cb);

		// Callback for find_successor in on_new_raw_message_delay_cb
		void on_new_raw_message_find_successor_cb(cb_onrm cb, ptr<incognito_raw_request> raw_msg, vec<chord_node> s, route search_path, chordstat status);

		// Callback for encrypt in on_new_raw_message_find_successor_cb
		void on_new_raw_message_encrypt_cb(cb_onrm cb, chord_node n, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res);

		// This method encrypts reply (raw_msg) and sends it
		void on_enc_message_onrm_cb(user_args *a, ptr<incognito_raw_request> raw_msg);
		//Usunąć: void send_reply(user_args *a,ptr<incognito_raw_request> raw_msg);

		// Callback for encrypt in on_enc_message_onrm_cb
		void on_enc_message_res_encrypt_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res);
		//Usunąć: void send_reply_encrypt_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res);
	// }}}
	
	// {{{ Diffie-Hellman implementation:
	public:
		// Call INCOGNITOPROC_DHKEY_EXCHANGE on node n providing p,g,pubkey as parameters
		void dh_exchange(chord_node &n, bigint p, bigint g, bigint pubkey, cb_dh_exchange cb);
	protected:
		// Called by dispatch() - handle INCOGNITOPROC_DHKEY_EXCHANGE
		void on_dhkey_exchange(user_args *a);
		// Callback for doRPC in dh_exchange
		void dh_exchange_cb(cb_dh_exchange cb,incognito_dh_res *res,clnt_stat err);
	// }}}
	protected:

	// Misc methods
		void doRPC (ptr<location> n, const rpc_program &prog, int procno,
                ptr<void> in, void *out, aclnt_cb cb, cbtmo_t cb_tmo = NULL);

		void doRPC (const chord_node &n, const rpc_program &prog, int procno,
                ptr<void> in, void *out, aclnt_cb cb, cbtmo_t cb_tmo = NULL);

		void doRPC (const chord_node_wire &n, const rpc_program &prog, int procno,
                ptr<void> in, void *out, aclnt_cb cb, 
		                  cbtmo_t cb_tmo = NULL);

	private:
		ptr<vnode>	_host_node;
		ptr<dhashcli>	_dhcli;
		ptr<keymngr>	_keymngr;
		ptr<encmngr>	_encmngr;
};
#endif	/* INCOGNITO_INCOGNITO_H */
// vim: foldmethod=marker
